package com.ybear.ybutils.utils

import android.content.Context
import android.os.Handler
import android.view.View
import androidx.annotation.Px
import androidx.annotation.Size
import androidx.core.util.Consumer
import java.util.Timer
import java.util.TimerTask

/**
 * 工具类
 */
object Utils {
    private var isClick = true

    @JvmStatic
    fun reverse(arr: Array<Any?>) {
        val size = arr.size
        var i = 0
        val mid = size shr 1
        var j = size - 1
        while ( i < mid ) {
            swap( arr, i, j )
            i++
            j--
        }
    }

    @JvmStatic
    fun swap(arr: Array<Any?>, i: Int, j: Int) {
        val tmp = arr[i]
        arr[i] = arr[j]
        arr[j] = tmp
    }

    /**
     * 将对象转换为List<Map></Map><String></String>, String>
     * @param obj   转换的obj
     * @return      list
     */
    @JvmStatic
    fun objectToList(obj: Any?): List<Map<String, String?>>? {
        var key: String
        var value: String?
        val list: MutableList<Map<String, String?>> = ArrayList()
        val map: MutableMap<String, String?> = HashMap()
        if (obj is List<*>) {
            //获取列表中的Map（现在是Obj，所以需要转换）
            for (mapObj in obj) {
                /* 利用反射获取转换Map */
                val cls: Class<*> = mapObj?.javaClass ?: continue
                for (field in cls.declaredFields) {
                    try {
                        val fieldObj = field[mapObj]
                        field.isAccessible = true
                        key = field.name
                        value = fieldObj?.toString()
                        map[key] = value
                    } catch (e: IllegalAccessException) {
                        e.printStackTrace()
                        return null
                    }
                }
                list.add(map)
            }
        }
        return list
    }

    /**
     * px转dp
     * @param context       上下文
     * @param px            像素值
     * @return              返回的dp值
     */
    @JvmStatic
    fun px2Dp(context: Context?, px: Float): Float {
        return if (context == null) px else px / context.resources.displayMetrics.density + 0.5f
    }
    @JvmStatic
    fun px2Dp(context: Context?, px: Int): Int {
        return px2Dp(context, px.toFloat()).toInt()
    }

    /**
     * dp转px
     * @param context       上下文
     * @param dp            dip值
     * @return              返回的px值
     */
    @Px
    @JvmStatic
    fun dp2Px(context: Context?, dp: Float): Float {
        return if (context == null) dp else dp * context.resources.displayMetrics.density + 0.5f
    }
    @Px
    @JvmStatic
    fun dp2Px(context: Context?, dp: Int): Int {
        return dp2Px(context, dp.toFloat()).toInt()
    }

    /**
     * map转set
     * @param map   Map
     * @return Set
     */
    @JvmStatic
    fun <T> map2Set(map: Map<String?, T>): Set<T?> {
        val ret: MutableSet<T?> = HashSet()
        for (key in map.keys) ret.add(map[key])
        return ret
    }

    /**
     * 点击间隔延迟
     * @param listener    回调
     * @param delay       延迟时间
     * @param handler     通过子线程返回，否则view可能会闪退
     */
    @Synchronized
    @JvmStatic
    fun clickIntervalDelay(listener: CallbackDelayListener?, delay: Int, handler: Handler?) {
        if ( !isClick ) return
        isClick = false
        listener?.onDelay()
        val run = Runnable { isClick = true }
        //点击间隔延迟
        handler?.postDelayed( run, delay.toLong() ) ?: Timer()
            .schedule(object : TimerTask() {
                override fun run() {
                    run.run()
                }
            }, delay.toLong())
    }

    @Synchronized
    @JvmStatic
    fun clickIntervalDelay(
        listener: CallbackDelayListener?,
        delay: Int,
        handler: com.ybear.ybutils.utils.handler.Handler?
    ) {
        clickIntervalDelay(listener, delay, handler?.osHandler)
    }

    @JvmStatic
    fun clickIntervalDelay(mCallbackIntervalDelayListener: CallbackDelayListener?) {
        clickIntervalDelay(mCallbackIntervalDelayListener, 500, null as Handler?)
    }

    private var mFirstTime: Long = 0
    @JvmStatic
    fun doubleClickListener(call: Consumer<Boolean?>?) {
        val secondTime = System.currentTimeMillis()
        val isDoubleClick: Boolean
        if (secondTime - mFirstTime > 2000) {
            mFirstTime = secondTime
            isDoubleClick = false
        } else {
            mFirstTime = 0
            isDoubleClick = true
        }
        call?.accept(isDoubleClick)
    }

    /**
     * 计算长宽比
     * @param fromWidth         原始宽度
     * @param fromHeight        原始高度
     * @param toWidthOrHeight   目标宽度或高度
     * @param isWidth           `toWidthOrHeight`是宽度还是高度
     * @return                  `isWidth`为true则返回结果为高度，否则为宽度
     */
    @JvmStatic
    fun calcAspectRatio(
        fromWidth: Int, fromHeight: Int,
        toWidthOrHeight: Int, isWidth: Boolean
    ): Int {
        val ret: Double
        val ratio = fromHeight.toDouble() / fromWidth.toDouble()
        ret = if (isWidth) {
            toWidthOrHeight.toDouble() * ratio
        } else {
            toWidthOrHeight.toDouble() / ratio
        }
        return ret.toInt()
    }

    /**
     * 获取View的实际高宽
     * @param view      View
     * @param size      接收高宽的数组
     */
    @JvmStatic
    fun getViewSize(view: View, @Size(2) size: IntArray) {
        val lp = view.layoutParams
        val w: Int
        val h: Int
        if ( lp != null && lp.width > 0 && lp.height > 0 ) {
            w = lp.width
            h = lp.height
        } else if ( view.width > 0 && view.height > 0 ) {
            w = view.width
            h = view.height
        } else {
            //测量
            view.measure(0, 0)
            w = view.measuredWidth.coerceAtLeast( view.width )
            h = view.measuredHeight.coerceAtLeast( view.height )
        }
        size[ 0 ] = w
        size[ 1 ] = h
    }

    /**
     * 为空抛异常，否则返回
     * @param obj   检查的obj
     * @param <T>   当前obj的反射
     * @return      obj
    </T> */
    @JvmStatic
    fun <T> requireNonNull(obj: T?): T {
        if (obj != null) return obj
        throw NullPointerException("this is Null")
    }

    interface CallbackDelayListener {
        fun onDelay()
    }
}